iT邦幫忙

2026 iThome 鐵人賽

DAY 7
0
AI Engineering

從對話到照護:30 天打造高齡智慧健康 AI Companion系列 第 7 篇

Day 07|讓 AI 邊生成邊說:打造 Streaming Voice Pipeline

  • 分享至 

  • xImage
  •  

Day 06 我把目前的語音對話流程拆開來看,發現最大的問題不是某個模型特別慢,而是整條 Pipeline 採用 Sequential 的方式執行。

目前流程大致是:

Speech End
↓
Final STT
↓
LLM 完整生成
↓
TTS 完整合成
↓
Playback

每一個階段都必須等待上一個階段全部完成,使用者才會聽到 AI 的第一句話。

所以 Day 07 的目標,就是把這條流程改成 Streaming Voice Pipeline。

Streaming 不一定代表模型本身計算得更快,而是讓不同階段不需要彼此等待完整結果,而可以更早開始工作。


Day 02 的 Rolling Transcription

Day 02 做 STT 時,我使用的是 Rolling Transcription。

概念是每隔固定時間,重新辨識目前累積的音訊:

0~2 秒 → STT
0~4 秒 → STT
0~6 秒 → STT

所以畫面上雖然可以持續看到辨識結果更新,看起來很像 Streaming,但實際上每次還是重新處理前面的音訊。

因此它比較接近:

Rolling / Pseudo-Streaming ASR

而真正的 Streaming ASR,則是持續接收新的 Audio Chunk,保留前面的處理狀態,再增量產生新的 Partial Result。

可以簡單比較:

Day 02:Rolling Transcription
→ 每隔 2 秒重新辨識累積音訊

Day 07:Streaming ASR
→ 持續接收 Audio Chunk
→ 保留前面的狀態
→ 增量輸出 Partial

這也是從 Day 02 到 Day 07 很明顯的一個技術演進。


LLM Token Streaming

完成 STT 之後,下一個要改的就是 LLM。

原本流程是:

Final STT
↓
LLM
↓
完整 Response
↓
TTS

也就是一定要等整段回答全部生成完成,才能交給 TTS。

今天則改成 LLM Token Streaming。

LLM 在生成內容時,會持續輸出新的 Token,而不是等全部完成才一次回傳。

例如:

今天
今天如果
今天如果覺得
今天如果覺得有點累
...

這樣就代表,後面的 TTS 其實可以提前開始工作。

但這裡也不能每一個 Token 都直接丟給 TTS。

如果變成:

今 → TTS
天 → TTS
記 → TTS
得 → TTS

不但會產生大量 TTS 呼叫,播放出來也會非常破碎。

所以中間需要加入一層 Buffer。


Sentence / Chunk Buffer

我在 LLM 和 TTS 中間加入了 Sentence / Chunk Buffer。

流程變成:

LLM Token Streaming
↓
Text Buffer
↓
累積到適合長度
↓
切成 Chunk
↓
TTS

例如 LLM 已經產生:

今天如果覺得有點累,

遇到逗號或累積到一定長度後,就可以先把這一段送進 TTS。

同時間,LLM 繼續生成:

可以先休息一下,不要太勉強自己。

這樣就不用等完整答案生成完畢。

不過 Chunk 的大小也需要調整。

如果切太短:

今天 /
記得 /
多喝水 /

語音容易變得破碎、不自然。

但如果切太長,又會失去 Streaming 提早播放的優勢。

因此 Chunk 的切分必須在自然度與延遲之間取得平衡。


Chunked TTS 與 Playback Queue

目前 TTS 我先使用 Kokoro 做 Chunked TTS。

也就是:

Text Chunk 1 → Audio 1
Text Chunk 2 → Audio 2
Text Chunk 3 → Audio 3

它還不是真正逐 Audio Frame 輸出的 Streaming TTS,但已經可以讓 LLM 與 TTS 部分重疊執行。

接著,我再加入 Playback Queue。

當 TTS 產生 Audio Chunk 後,就依序放進播放佇列:

Audio 1
↓
Audio 2
↓
Audio 3

播放器只需要持續從 Queue 裡拿下一段音訊播放。

這時就會出現真正的 Pipeline 重疊:

Playback:播放 Audio 1
TTS:產生 Audio 2
LLM:生成 Chunk 3

也就是三個階段可以同時進行。


Sequential vs Streaming

原本是:

STT
↓
LLM 完整生成
↓
TTS 完整生成
↓
Playback

今天則變成:

Mic
↓
Rolling / Streaming ASR
↓
LLM Token Streaming
↓
Sentence / Chunk Buffer
↓
Chunked TTS
↓
Playback Queue
↓
AI 邊生成邊說

Streaming 最大的改變不是讓整段回答更快完成,而是讓第一段語音可以更早播放。

因此今天我再次觀察:

Speech End → First Audio

這個指標。

因為對使用者來說,真正影響體感的不是 AI 什麼時候「全部回答完」,而是使用者停止說話後,要等多久才能聽到 AI 開始回應。


今天遇到的問題

今天最大的問題變成:

Chunk 到底要怎麼切?

目前需要考慮:

遇到逗號要不要切?
句號一定要切嗎?
最少需要幾個字?
最多要等待多久?
Audio Queue 要預先累積多少?

Chunk 太小會讓語音變得零碎,Chunk 太大又會增加等待時間。

所以 Streaming 並不是單純把 stream=True 打開就完成,真正需要處理的是 LLM、TTS 與 Playback 之間的協調。


Day 07 完成

Day 06 我找出了 Sequential Pipeline 中大量等待的問題。

Day 07 則開始把 LLM、TTS 與 Playback 改成可以重疊執行。

今天最重要的一個觀念是:

Streaming 不一定讓模型本身算得更快,而是讓不同階段不用彼此等待完整結果,可以更早開始工作。

現在 AI Companion 已經從:

使用者說完
↓
AI 想完
↓
AI 合成完
↓
AI 才開始說

慢慢變成:

使用者說完
↓
AI 開始生成
↓
前面的文字先做 TTS
↓
第一段語音先播放
↓
後面的內容繼續生成

也就是開始做到真正的「邊生成、邊說」。

但現在還有下一個問題:

如果 AI 正在講話,而使用者突然說:

「等等,我不是這個意思。」

系統目前還是會繼續把原本的回答講完。

所以 Day 08 要做的,就是 Barge-in 即時打斷,讓 AI 在說話時也能偵測使用者新的語音,立即停止 Playback、清空 Audio Queue,並取消目前的 TTS 與 LLM,重新回到 Listening 狀態。


上一篇
Day 06|語音對話到底慢在哪?拆解 AI Companion 的延遲
下一篇
Day 08|別等 AI 說完:加入 Barge-in 即時打斷
系列文
從對話到照護:30 天打造高齡智慧健康 AI Companion 共 9 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言